package com.jweb.core.handle;

import java.io.PrintWriter;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.jweb.annotaion.JParam;
import com.jweb.core.JWebFilter;
import com.jweb.core.inter.HandleInterceptor;
import com.jweb.util.FormatUtil;
import com.jweb.util.HttpServletRequestUtil;

/**
 * 请求处理中心
 * 
 * @author Yuan
 */
public class Handle {
	// private String nowUrl = "";
	// private static final Class<?>[] NULL_PARAS = new Class<?>[0];
	private Logger log = LoggerFactory.getLogger(getClass());

	protected static final Map<Integer, String> errPage = new HashMap<Integer, String>() {
		private static final long serialVersionUID = 1L;

		{
			this.put(401,
					"<html><head><title>401 Unauthorized</title></head><body bgcolor='white'><center><h1>401 Unauthorized</h1></center><hr><center></center></body></html>");
			this.put(403,
					"<html><head><title>403 Forbidden</title></head><body bgcolor='white'><center><h1>403 Forbidden</h1></center><hr><center></center></body></html>");
			this.put(404,
					"<html><head><title>404 Not Found</title></head><body bgcolor='white'><center><h1>404 Not Found</h1></center><hr><center></center></body></html>");
			this.put(
					500,
					"<html><head><title>500 Internal Server Error</title></head><body bgcolor='white'><center><h1>500 Internal Server Error</h1></center><hr><center></center></body></html>");
		}
	};

	/**
	 * 请求处理中心[核心]
	 */
	public final void handle(String target, HttpServletRequest request, HttpServletResponse response, boolean[] isHandled) throws InstantiationException,
			IllegalAccessException, IllegalArgumentException, SecurityException, NoSuchFieldException {
		target = formatURL(target);
		isHandled[0] = true;
		Exception ex = null;
		Controller controller = null;
		Action action = null;
		int errorCode = 500;
		Object retObj = null;
		try {
			for (HandleInterceptor h : JWebFilter.getAllhandleinter())
				if (!h.preHandle(request, response)) // 前拦截
					return;// 直接返回，不做操作
			action = getAction(target);
			controller = ((Controller) JWebFilter.getControllerbean().get(action.getControllerKey()));
			controller.load(request, response, action.getParamList(), HttpServletRequestUtil.getParameterMap(request), action.getViewPath());
			retObj = doAction(action, controller);// 执行操作
		} catch (ActionException e) {
			ex = e;
			errorCode = e.getErrorCode();
			e.printStackTrace();
		} catch (Exception e) {
			ex = e;
			errorCode = 500;
			e.printStackTrace();
		}
		try {
			for (HandleInterceptor h : JWebFilter.getAllhandleinter())
				h.afterCompletion(request, response, ex); // 后拦截
		} catch (Exception e2) {
			e2.printStackTrace();
		}
		if (ex == null)
			toClient(controller, request, response, retObj);// 正常返回
		else
			toWriter(errPage.get(errorCode), "HTML", response);// 错误返回
	}

	/**
	 * 精髓所在！！！(针对静态化页面,RESTful风格)<br>
	 * 对URL的处理以对应不通的Controller,method,param<br>
	 * 总共分为下列4种URL格式： <br>
	 * 1: http://abc.com/controllerKey ---> 00 <br>
	 * 2: http://abc.com/controllerKey/para ---> 01 <br>
	 * 3: http://abc.com/controllerKey/method ---> 10 <br>
	 * 4: http://abc.com/controllerKey/method/para ---> 11
	 * 
	 */
	private Action getAction(String url) {
		Class<? extends Controller> curCla = null;
		for (Entry<String, Class<? extends Controller>> entry : JWebFilter.getControllerclass().entrySet()) {
			if (url.indexOf(entry.getKey()) == 0) {
				curCla = entry.getValue();
				String ourl = url.substring(entry.getKey().length());
				String paramStr = "";
				String methodName = FormatUtil.isEmpty(ourl) ? "" : getFirstN(ourl);
				Method method = FormatUtil.isEmpty(methodName) ? null : getMethod(curCla.getMethods(), methodName);
				if (method == null) {
					paramStr = FormatUtil.isEmpty(ourl) ? "" : ourl.substring(1);
					methodName = cutName(curCla.getSimpleName());
					method = getMethod(curCla.getMethods(), methodName);
				} else {
					paramStr = ourl.substring(1 + methodName.length());
					paramStr = (paramStr.indexOf("/") == 0) ? paramStr.substring(1) : paramStr;
				}
				if (method != null)
					return new Action(entry.getKey(), curCla, method, methodName, paramStr);
			}
		}
		log.error("Action Not Found:" + url);
		throw new ActionException(404);
	}

	private String getFirstN(String ourl) {
		String name = "";
		if (ourl.lastIndexOf("/") == 0)
			name = ourl.substring(1);
		else
			name = ourl.substring(1, ourl.substring(1).indexOf("/") + 1);
		return name;
	}

	private Method getMethod(Method[] ms, String methodName) {
		Method method = null;
		for (Method m : ms)
			if (m.getName().equals(methodName))
				method = m;
		return method;
	}

	/**
	 * 针对URL:00格式 <br>
	 * 如果控制类是以xxxController.java命名，则默认调用类中xxxManager()方法 <br>
	 * 否则该控制类的默认方法为：当前类名+Manager()方法。
	 */
	private String cutName(String args) {
		String b = args.substring(args.length() - 10);
		if (b.equalsIgnoreCase("controller")) {
			return (args.substring(0, args.length() - 10)) + "Manager";
		} else {
			return (args) + "Manager";
		}
	}

	/**
	 * 调用控制类中指定方法
	 * 
	 * @throws InstantiationException
	 */
	private Object doAction(Action action, Controller controller) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException,
			InstantiationException {
		Method[] ms = controller.getClass().getDeclaredMethods();
		for (Method m : ms) {
			m.setAccessible(true);
			if (m.getName().equalsIgnoreCase("init")) {
				m.invoke(controller, new Object[0]);
				break;
			}
		}
		Object[] obj = getMParams(action.getMethod(), controller);
		return action.getMethod().invoke(controller, obj);
	}

	private Object[] getMParams(Method me, Controller controller) throws InstantiationException, IllegalAccessException {
		Class<?>[] types = me.getParameterTypes();
		Annotation[][] anno = me.getParameterAnnotations();
		Object[] params = new Object[types.length];
		for (int i = 0; i < types.length; i++) {
			String type = types[i].getSimpleName();
			String param = "";
			String value = "";
			Annotation ans = null;
			String jval = null;
			if (anno[i].length > 0) {
				ans = anno[i][0];
				JParam jp = (JParam) ans;
				jval = jp.value();
				if (jval.startsWith("${")) {
					param = jval.substring(2, jval.length() - 1);
					if (FormatUtil.isNumber(param)) {
						int index = FormatUtil.toInt(param);
						value = controller.getParamURL_String(index - 1);
					} else {
						value = controller.getParameter(param);
					}
				} else {
					value = controller.getParameter(jval);
				}
			}
			Object val = FormatUtil.baseChangeType(types[i], value);
			if (val != null) {
				params[i] = val;
			} else if (type.equals("HttpServletRequest")) {
				params[i] = controller.request.get();
			} else if (type.equals("HttpServletResponse")) {
				params[i] = controller.response.get();
			} else {
				try {
					Object obj = types[i].newInstance();
					Method[] ms = types[i].getMethods();
					for (Method m : ms) {
						String mn = m.getName();
						if (mn.startsWith("set") && m.getParameterTypes().length == 1) {
							String pv = HttpServletRequestUtil.getRequestIgnoreCaseParameter(controller.request.get(), mn.substring(3));
							if (pv != null) {
								m.invoke(obj, FormatUtil.baseChangeType(m.getParameterTypes()[0], pv));
							}
						}
					}
					params[i] = obj;
					//System.err.println(">>" + FormatUtil.toJSONString(obj));
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}

		return params;
	}

	/** 返回客户端 */
	private boolean toClient(Controller controller, HttpServletRequest request, HttpServletResponse response, Object retObj) {
		try {
			int type = controller.getReturntype();
			String strV = FormatUtil.toString(controller.getReturnView());
			if (type == 0 && retObj != null) {
				type = 3;
				strV = FormatUtil.toJSONString(retObj);
			}
			if (type == 1) {
				if (strV.endsWith(JWebFilter.getConstants("ViewSuffix"))) {
					strV = JWebFilter.getConstants("ViewPrefix") + "/" + strV;
				}
				strV = FormatUtil.formatPath(strV);
				request.getRequestDispatcher(strV).forward(request, response); // 1、服务器内转发
				log.info("[Forward]:" + strV);// 2、直接后端跳转
			} else if (type == 2) {
				if (!strV.startsWith("http"))
					strV = request.getContextPath() + strV;
				strV = FormatUtil.formatPath(strV);
				response.sendRedirect(strV); // 3、重定向
				log.info("[Redirect]:" + strV);
			} else if (type == 3) {
				toWriter(strV, "JSON", response); // 3、打印JSON
			} else if (type == 4) {
				toWriter(strV, "TEXT", response); // 4、打印Text
			} else if (type == 5) {
				toWriter(strV, "HTML", response); // 4、打印Html
			} else {
				if (response.getContentType() == null) {
					strV = FormatUtil.formatPath(controller.getDefaultView());
					request.getRequestDispatcher(strV).forward(request, response); // 5、返回默认页面
					log.info("[ForwardDefault]:" + strV);
				} else {
					System.out.println(response.getContentType());
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			// try {
			// response.flushBuffer();//不知道为啥会报：Software caused connection
			// abort: socket write error
			// } catch (IOException e) {
			// e.printStackTrace();
			// }
		}
		return false;
	}

	/** 4、打印信息 */
	private void toWriter(String str, String type, HttpServletResponse response) {
		PrintWriter out = null;
		try {
			String encod = JWebFilter.getConstants().get("encoding");
			// response.setCharacterEncoding(encod);
			if (type.equals("JSON"))
				response.setContentType("application/json; charset=" + encod);
			else if (type.equals("HTML"))
				response.setContentType("text/html; charset=" + encod);
			else if (type.equals("TEXT"))
				response.setContentType("text/plain; charset=" + encod);
			out = response.getWriter(); // 直接输出
			out.append(str);
			log.info("response.getContentType=" + response.getContentType());
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			if (out != null) {
				out.flush();
				out.close();
			}
		}
	}

	/** 简单处理下URL,便于解析 */
	private String formatURL(String target) {
		if (JWebFilter.getContextPathLength() != 0)
			target = target.substring(JWebFilter.getContextPathLength());
		int wenI = target.lastIndexOf("?");
		if (wenI != -1)
			target = target.substring(0, wenI);
		int dianI = target.lastIndexOf(".");
		if (dianI != -1)
			if (!FormatUtil.isNumber(target.substring(dianI + 1)))
				target = target.substring(0, dianI);
		return target;
	}
}
